package com.taoz.mianshiwa.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.taoz.mianshiwa.common.BaseResponse;
import com.taoz.mianshiwa.common.DeleteRequest;
import com.taoz.mianshiwa.common.ErrorCode;
import com.taoz.mianshiwa.common.ResultUtils;
import com.taoz.mianshiwa.constant.UserConstant;
import com.taoz.mianshiwa.exception.ThrowUtils;
import com.taoz.mianshiwa.model.dto.user.*;
import com.taoz.mianshiwa.model.entity.User;
import com.taoz.mianshiwa.model.vo.LoginUserVO;
import com.taoz.mianshiwa.model.vo.UserVO;
import com.taoz.mianshiwa.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import static com.taoz.mianshiwa.service.impl.UserServiceImpl.SALT;

/**
 * 用户接口
 */
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

    @Resource
    private UserService userService;

    /**
     * 获取用户的签到记录
     */
    @SaCheckLogin
    @GetMapping("/get/signInList")
    public BaseResponse<List<Integer>> getSignInList(Integer year) {
        // 参数校验
        ThrowUtils.throwIf(year == null || year <= 0, ErrorCode.PARAMS_ERROR, "请求年份不合法");

        // 获取用户的签到日期的列表
        List<Integer> signInList = userService.getSignInList(year, StpUtil.getLoginIdAsLong());

        return ResultUtils.success(signInList);
    }


    /**
     * 用户签到
     */
    @SaCheckLogin
    @PostMapping("/signIn")
    public BaseResponse<Boolean> signIn() {
        // 登录用户进行签到
        boolean result = userService.signIn(StpUtil.getLoginIdAsLong());

        return ResultUtils.success(result);
    }

    /**
     * 用户注册
     */
    @PostMapping("/register")
    public BaseResponse<Long> userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
        // 参数校验
        String userAccount = userRegisterRequest.getUserAccount();
        String userPassword = userRegisterRequest.getUserPassword();
        String checkPassword = userRegisterRequest.getCheckPassword();
        ThrowUtils.throwIf(StringUtils.isAnyBlank(userAccount, userPassword, checkPassword), ErrorCode.PARAMS_ERROR, "请求参数不合法");

        // 获取注册结果,注册成功的用户id
        long registerUserId = userService.userRegister(userAccount, userPassword, checkPassword);

        return ResultUtils.success(registerUserId);
    }

    /**
     * 用户登录
     */
    @PostMapping("/login")
    public BaseResponse<LoginUserVO> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
        // 参数校验
        String userAccount = userLoginRequest.getUserAccount();
        String userPassword = userLoginRequest.getUserPassword();
        ThrowUtils.throwIf(StringUtils.isAnyBlank(userAccount, userPassword), ErrorCode.PARAMS_ERROR, "账号和密码不能为null");

        // 进行登录，成功返回用户的VO对象
        LoginUserVO loginUserVO = userService.userLogin(userAccount, userPassword, request);

        return ResultUtils.success(loginUserVO);
    }

    /**
     * 用户注销
     */
    @SaCheckLogin
    @PostMapping("/logout")
    public BaseResponse<Boolean> userLogout(HttpServletRequest request) {
        // 调用用户注销方法
        boolean result = userService.userLogout(request);

        return ResultUtils.success(result);
    }

    /**
     * 获取当前登录用户
     * 正常情况下登录之后都有缓存，可以直接从缓存中哪去数据
     * 该方法应该达到将数据库用户和缓存用户同步的效果
     */
    @SaCheckLogin
    @GetMapping("/get/login")
    public BaseResponse<LoginUserVO> getLoginUser() {
        // 拿到数据库中的用户
        User user = userService.getLoginUser();

        return ResultUtils.success(userService.getLoginUserVO(user));
    }

    // 提供给管理员管理用户的接口

    /**
     * 创建用户
     */
    @PostMapping("/add")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Long> addUser(@RequestBody UserAddRequest userAddRequest) {
        // 参数校验
        String userAccount = userAddRequest.getUserAccount();
        String userPassword = userAddRequest.getUserPassword();
        ThrowUtils.throwIf(StringUtils.isAnyBlank(userAccount, userPassword), ErrorCode.PARAMS_ERROR, "至少需要传入账号和密码");
        ThrowUtils.throwIf(!UserConstant.validRole(userAddRequest.getUserRole()), ErrorCode.PARAMS_ERROR);

        synchronized (userAccount.intern()) {
            // 账户不能重复
            // 使用数据库的覆盖索引，避免回表查询
            User user = userService.lambdaQuery().select(User::getUserAccount).eq(User::getUserAccount, userAccount).one();
            ThrowUtils.throwIf(user != null, ErrorCode.PARAMS_ERROR, "账号已存在");

            // 存入数据库的密码需要加密处理，在后端层面进行加密操作
            User newUser = new User();
            BeanUtils.copyProperties(userAddRequest, newUser);
            String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
            newUser.setUserPassword(encryptPassword);
            // mp的save方法如果save成功会将生成的Id注入给newUser
            boolean ok = userService.save(newUser);
            ThrowUtils.throwIf(!ok, ErrorCode.SYSTEM_ERROR, "注册失败，数据库错误");

            return ResultUtils.success(newUser.getId());
        }
    }

    /**
     * 删除用户
     */
    @PostMapping("/delete")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> deleteUser(@RequestBody DeleteRequest deleteRequest) {
        ThrowUtils.throwIf(deleteRequest.getId()  == null || deleteRequest.getId() <= 0, ErrorCode.PARAMS_ERROR, "参数必须为正整数");

        boolean b = userService.removeById(deleteRequest.getId());

        return ResultUtils.success(b);
    }

    /**
     * 更新用户
     */
    @PostMapping("/update")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> updateUser(@RequestBody UserUpdateRequest userUpdateRequest) {
        ThrowUtils.throwIf(userUpdateRequest.getId() == null || userUpdateRequest.getId() <= 0, ErrorCode.PARAMS_ERROR, "参数错误");

        User user = new User();
        BeanUtils.copyProperties(userUpdateRequest, user);
        boolean result = userService.updateById(user);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);

        return ResultUtils.success(true);
    }

    /**
     * 根据 id 获取用户全部信息
     */
    @GetMapping("/get")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<User> getUserById(Long id) {
        // 参数校验
        ThrowUtils.throwIf(id == null || id <= 0, ErrorCode.PARAMS_ERROR, "id必须为正整数");

        User user = userService.getById(id);
        ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR);

        return ResultUtils.success(user);
    }

    /**
     * 根据 id 获取包装类
     */
    @GetMapping("/get/vo")
    public BaseResponse<UserVO> getUserVOById(Long id) {
        // 参数校验
        ThrowUtils.throwIf(id == null || id <= 0, ErrorCode.PARAMS_ERROR, "id必须为正整数");

        User user = userService.getById(id);
        UserVO userVO = userService.getUserVO(user);

        return ResultUtils.success(userVO);
    }

    /**
     * 分页获取用户列表（仅管理员）
     */
    @PostMapping("/list/page")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<User>> listUserByPage(@RequestBody UserQueryRequest userQueryRequest) {
        long current = userQueryRequest.getCurrent();
        long size = userQueryRequest.getPageSize();
        Page<User> userPage = userService.page(new Page<>(current, size),
                userService.getQueryWrapper(userQueryRequest));

        return ResultUtils.success(userPage);
    }

    /**
     * 分页获取用户VO列表
     */
    @PostMapping("/list/page/vo")
    public BaseResponse<Page<UserVO>> listUserVOByPage(@RequestBody UserQueryRequest userQueryRequest) {
        long current = userQueryRequest.getCurrent();
        long size = userQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);

        Page<User> userPage = userService.page(new Page<>(current, size),
                userService.getQueryWrapper(userQueryRequest));
        Page<UserVO> userVOPage = new Page<>(current, size, userPage.getTotal());
        List<UserVO> userVO = userService.getUserVO(userPage.getRecords());
        userVOPage.setRecords(userVO);

        return ResultUtils.success(userVOPage);
    }

    /**
     * 更新个人信息
     */
    @SaCheckLogin
    @PostMapping("/update/my")
    public BaseResponse<Boolean> updateMyUser(@RequestBody UserUpdateMyRequest userUpdateMyRequest) {
        User user = new User();
        BeanUtils.copyProperties(userUpdateMyRequest, user);
        user.setId(StpUtil.getLoginIdAsLong());
        boolean result = userService.updateById(user);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);

        return ResultUtils.success(true);
    }
}
